#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>

#define DEVMEM         "/dev/mem"

#define PAGE_SIZE       0x1000
#define PAGE_MASK       (PAGE_SIZE-1)

#define READ_SIZE		256


static void print_usage(char *app)
{
	fprintf(stdout, "Usage:  %s phy_addr [value] \n", app);
	fprintf(stdout, "\n");
}

static void print_version(void)
{
	printf("Build GCC Version: %s \n", __VERSION__);
	printf("Build Date： %s \n", __DATE__);
	printf("Build Time %s \n", __TIME__);
	printf("\n");
}

static void read_mem(unsigned int phyaddr, void *mapaddr)
{
	int i;
	unsigned int *r_mem = (unsigned int *)mapaddr;
	unsigned char offset = sizeof(unsigned int);

	for(i = 0; i < READ_SIZE / offset; i += offset){
		printf("%08X: %08X %08X %08X %08X\n",
				phyaddr + i * offset, 
				*(r_mem + i + 0), 
				*(r_mem + i + 1), 
				*(r_mem + i + 2), 
				*(r_mem + i + 3));
	}

}

static void write_mem(void *mapaddr, unsigned int value)
{
	unsigned int *w_mem = (unsigned int *)mapaddr;

	*w_mem = value;
}


int main(int argc, char* argv[])
{
    int fd;
    char *mbase;
    unsigned int phyaddr;
	unsigned int value;

	unsigned int offset;

	if(argc < 2){
		print_usage(argv[0]); 
        print_version();
	}

    phyaddr = strtoul(argv[1], 0, 16);
	offset = phyaddr & PAGE_MASK;

    fd = open(DEVMEM, O_RDWR| O_SYNC, 0655);
    if (fd == -1) {
        perror("open");
        exit(-1);
    }

    mbase = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (phyaddr & ~PAGE_MASK));
    if (mbase == MAP_FAILED) {
        printf("map failed %s\n",strerror(errno));
		close(fd);
		return -1;
    }
    
	if(argc == 2){
		read_mem(phyaddr, mbase + offset);
	}else if(argc == 3){
		value = strtoul(argv[2], 0, 0);
		
		write_mem(mbase + offset, value);
	}
    
    munmap(mbase, PAGE_SIZE);
	close(fd);

    return 0;
}
